package com.emm.yixun.common.utils;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 校验证件号码是否正确
 * @author junze.liu
 *
 */
public class VerifyIDNumber {
	
	/**
	 * 身份证校验因子
	 */
	final static int[] PARITYBIT = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
    final static int[] POWER_LIST = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10,5, 8, 4, 2};
	final static Map<Integer, String> zoneNum = new HashMap<Integer, String>();
    static {
        zoneNum.put(11, "北京");
        zoneNum.put(12, "天津");
        zoneNum.put(13, "河北");
        zoneNum.put(14, "山西");
        zoneNum.put(15, "内蒙古");
        zoneNum.put(21, "辽宁");
        zoneNum.put(22, "吉林");
        zoneNum.put(23, "黑龙江");
        zoneNum.put(31, "上海");
        zoneNum.put(32, "江苏");
        zoneNum.put(33, "浙江");
        zoneNum.put(34, "安徽");
        zoneNum.put(35, "福建");
        zoneNum.put(36, "江西");
        zoneNum.put(37, "山东");
        zoneNum.put(41, "河南");
        zoneNum.put(42, "湖北");
        zoneNum.put(43, "湖南");
        zoneNum.put(44, "广东");
        zoneNum.put(45, "广西");
        zoneNum.put(46, "海南");
        zoneNum.put(50, "重庆");
        zoneNum.put(51, "四川");
        zoneNum.put(52, "贵州");
        zoneNum.put(53, "云南");
        zoneNum.put(54, "西藏");
        zoneNum.put(61, "陕西");
        zoneNum.put(62, "甘肃");
        zoneNum.put(63, "青海");
        zoneNum.put(64, "宁夏");
        zoneNum.put(65, "新疆");
        zoneNum.put(71, "台湾");
        zoneNum.put(81, "香港");
        zoneNum.put(82, "澳门");
        zoneNum.put(91, "外国");
    }
    /**
     * 身份证验证
     *@param certNo
     *@return 是否有效 null和"" 都是false
     */
    public static boolean verifyIDCard(String certNo){
        if(certNo == null || (certNo.length() != 15 && certNo.length() != 18)) {
            return false;
        }
        final char[] cs = certNo.toUpperCase().toCharArray();
        //校验位数
        int power = 0;
        for(int i=0; i<cs.length; i++){
            if(i==cs.length-1 && cs[i] == 'X')
                break;//最后一位可以 是X或x
            if(cs[i]<'0' || cs[i]>'9')
                return false;
            if(i < cs.length -1){
                power += (cs[i] - '0') * POWER_LIST[i];
            }
        }
        //校验区位码
        if(!zoneNum.containsKey(Integer.valueOf(certNo.substring(0,2)))){
            return false;
        }
        //校验年份
        String year = certNo.length() == 15 ? getIdcardCalendar() + certNo.substring(6,8) :certNo.substring(6, 10);
        final int iyear = Integer.parseInt(year);
        if(iyear < 1900 || iyear > Calendar.getInstance().get(Calendar.YEAR)) {
            return false;
        }
        //校验月份
        String month = certNo.length() == 15 ? certNo.substring(8, 10) : certNo.substring(10,12);
        final int imonth = Integer.parseInt(month);
        if(imonth <1 || imonth >12){
            return false;
        }
        //校验天数     
        String day = certNo.length() ==15 ? certNo.substring(10, 12) : certNo.substring(12, 14);
        final int iday = Integer.parseInt(day);
        if(iday < 1 || iday > 31) {
            return false;      
        }
        //校验"校验码"
        if(certNo.length() == 15) {
            return true;
        }
        return cs[cs.length -1 ] == PARITYBIT[power % 11];
    }
    /**
     * 计算时间
     * @return
     */
    private static int getIdcardCalendar() {       
         GregorianCalendar curDay = new GregorianCalendar();
         int curYear = curDay.get(Calendar.YEAR);
         int year2bit = Integer.parseInt(String.valueOf(curYear).substring(2));         
         return year2bit;
    }    
 
	/**
	 * 校验 营业执照号码是否正确
	 * @param businesslicense
	 * @return
	 */
    public static boolean verifyBusinessLicense(String businesslicense) {
    	boolean flag = true;
    	if(businesslicense.length() == 18){
    		//验证18位的营业执照
    		flag = verifyBusinessLicense_18(businesslicense);
		} else if (businesslicense.length() == 15) {
			//验证15位的营业执照
			flag = verifyBusinessLicense_15(businesslicense);
		} else {
			System.out.println("营业执照号码长度错误！");
		    return false;
		}
    	return flag;
    }
 
    /**
     * 校验 营业执照号(15位)
     * @param businesslicense
     * @return
     */
    public static boolean verifyBusinessLicense_15(String code){
 
        String businesslicensePrex14 = code.substring(0,14);// 获取营业执照注册号前14位数字用来计算校验码
        String businesslicense15 = code.substring(14, code.length());// 获取营业执照号的校验码
        char[] chars = businesslicensePrex14.toCharArray();
        int[] ints = new int[chars.length];
        for(int i=0; i<chars.length;i++){
            ints[i] = Integer.parseInt(String.valueOf(chars[i]));
        }
        // 比较 填写的营业执照注册号的校验码和计算的校验码是否一致
        if(businesslicense15.equals(getCheckCode(ints)+"")){
            return true;
        }
        return false;
    }
 
    /**
     * 15位营业执照号校验码
     * @param ints
     * @return
     */
    private static int getCheckCode(int[] ints){
        if (null != ints && ints.length > 1) {
            int ti = 0;
            int si = 0;// pi|11+ti
            int cj = 0;// （si||10==0？10：si||10）*2
            int pj = 10;// pj=cj|11==0?10:cj|11
            for (int i=0;i<ints.length;i++) {
                ti = ints[i];
                pj = (cj % 11) == 0 ? 10 : (cj % 11);
                si = pj + ti;
                cj = (0 == si % 10 ? 10 : si % 10) * 2;
                if (i == ints.length-1) {
                    pj = (cj % 11) == 0 ? 10 : (cj % 11);
                    return pj == 1 ? 1 : 11 - pj;
                }
            }
        }
        return -1;
    }
	
    /**
     * 校验 营业执照号(18位)
     * @param businesslicense
     * @return
     */
    public static boolean verifyBusinessLicense_18(String code){
		String reg = "^([159Y]{1})([1239]{1})([0-9ABCDEFGHJKLMNPQRTUWXY]{6})([0-9ABCDEFGHJKLMNPQRTUWXY]{9})([0-90-9ABCDEFGHJKLMNPQRTUWXY])$";
		Pattern p = Pattern.compile(reg);
		Matcher m = p.matcher(code); 
		if(!m.matches()){
			System.out.println("营业执照号校验错误！");
		    return false;
		}
		String str = "0123456789ABCDEFGHJKLMNPQRTUWXY";
		int[] ws = {1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28};
		String[] codes = new String[2];
		codes[0] = code.substring(0, code.length() - 1); //获取前17位
		codes[1] = code.substring(code.length() - 1, code.length()); //获取第18位
		//验证第18位是否正确
		int sum = 0;
		for(int i = 0; i < 17; i++){
		    sum += str.indexOf(codes[0].charAt(i)) * ws[i];
		}
		int c18 = 31 - (sum % 31);
		if(c18 == 31){
		    c18 = 'Y';
		}else if(c18 == 30){
		    c18 = '0';
		}
		if (str.charAt(c18) != codes[1].charAt(0)) {
			System.out.println("营业执照号校验错误！第18位校验码下标号应为" + c18);
		    return false;
		}
		return true;
	}
    
    public static void main(String[] args){
    	//String test = "110108000000018"; // 15位营业执照号
    	//System.out.println(verifyBusinessLicense(test));
        
        //String test1 = "91320507695515077B"; // 18位营业执照号
        //System.out.println(verifyBusinessLicense(test1));
        
        boolean mark = verifyIDCard("320524197407313000");   
        System.out.println(mark);
    }
}
